package com.galen.manual.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.galen.manual.context.UserContextHolder;
import com.galen.manual.entity.FileRecord;
import com.galen.manual.mapper.FileRecordMapper;
import com.galen.manual.service.FileRecordService;
import com.galen.manual.utils.UserContextUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 文件记录服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileRecordServiceImpl implements FileRecordService {

    private final FileRecordMapper fileRecordMapper;

    @Override
    @Async
    public void saveFileRecordAsync(FileRecord fileRecord) {
        try {
            fileRecordMapper.insert(fileRecord);
            log.info("文件记录异步保存成功，ID: {}, 对象名称: {}", fileRecord.getId(), fileRecord.getObjectName());
        } catch (Exception e) {
            log.error("文件记录异步保存失败，对象名称: {}", fileRecord.getObjectName(), e);
        }
    }

    @Override
    public FileRecord createFileRecord(MultipartFile file, String objectName, String fileUrl,
                                      String fileCategory, Long businessId, String businessType,
                                      HttpServletRequest request) {
        try {
            FileRecord fileRecord = new FileRecord();

            // 基本信息
            fileRecord.setOriginalFilename(file.getOriginalFilename());
            fileRecord.setObjectName(objectName);
            fileRecord.setFileUrl(fileUrl);
            fileRecord.setFileSize(file.getSize());
            fileRecord.setContentType(file.getContentType());
            fileRecord.setFileCategory(fileCategory);

            // 业务关联信息
            fileRecord.setBusinessId(businessId);
            fileRecord.setBusinessType(businessType);

            // 上传用户信息
            try {
                if (request != null) {
                    fileRecord.setUploadUserId(UserContextHolder.getCurrentUserId());
                    fileRecord.setUploadUsername(UserContextHolder.getCurrentUsername());
                }
            } catch (Exception e) {
                log.warn("获取用户上下文失败，使用默认值", e);
                fileRecord.setUploadUserId(1L);
                fileRecord.setUploadUsername("system");
            }

            // 请求信息
            if (request != null) {
                fileRecord.setUploadIp(UserContextHolder.getClientIpAddress());
                fileRecord.setUserAgent(UserContextHolder.getUserAgent());
            }

            // 计算文件哈希值（用于去重）
            fileRecord.setFileHash(calculateFileHash(file));

            // 检查是否重复文件
            FileRecord existingFile = fileRecordMapper.selectByFileHash(fileRecord.getFileHash());
            if (existingFile != null) {
                fileRecord.setIsDuplicate(true);
                fileRecord.setStatus(1); // 标记为成功（因为是重复文件）
                log.info("检测到重复文件，哈希值: {}, 原文件ID: {}", fileRecord.getFileHash(), existingFile.getId());
            } else {
                fileRecord.setIsDuplicate(false);
                fileRecord.setStatus(0); // 标记为上传中
            }

            // 设置初始值
            fileRecord.setDownloadCount(0);

            // 异步保存到数据库
            saveFileRecordAsync(fileRecord);

            return fileRecord;

        } catch (Exception e) {
            log.error("创建文件记录失败", e);
            throw new RuntimeException("创建文件记录失败: " + e.getMessage());
        }
    }

    @Override
    public void updateFileStatus(Long id, Integer status, String errorMessage) {
        try {
            int result = fileRecordMapper.updateFileStatus(id, status, errorMessage);
            if (result > 0) {
                log.info("文件状态更新成功，ID: {}, 状态: {}", id, status);
            } else {
                log.warn("文件状态更新失败，未找到记录，ID: {}", id);
            }
        } catch (Exception e) {
            log.error("更新文件状态失败，ID: {}", id, e);
        }
    }

    @Override
    public FileRecord getFileRecordById(Long id) {
        return fileRecordMapper.selectById(id);
    }

    @Override
    public FileRecord getFileRecordByObjectName(String objectName) {
        return fileRecordMapper.selectByObjectName(objectName);
    }

    @Override
    public List<FileRecord> getFileRecordsByBusiness(Long businessId, String businessType) {
        return fileRecordMapper.selectByBusiness(businessId, businessType);
    }

    @Override
    public List<FileRecord> getFileRecordsByUserId(Long userId, Integer limit) {
        return fileRecordMapper.selectByUserId(userId, limit != null ? limit : 20);
    }

    @Override
    public List<FileRecord> getFileRecordsByCategory(String fileCategory, Integer limit) {
        return fileRecordMapper.selectByCategory(fileCategory, limit != null ? limit : 50);
    }

    @Override
    public void updateDownloadCount(Long id) {
        try {
            int result = fileRecordMapper.updateDownloadCount(id, LocalDateTime.now());
            if (result > 0) {
                log.debug("下载次数更新成功，文件ID: {}", id);
            }
        } catch (Exception e) {
            log.error("更新下载次数失败，文件ID: {}", id, e);
        }
    }

    @Override
    public void deleteFileRecord(Long id) {
        try {
            int result = fileRecordMapper.deleteById(id);
            if (result > 0) {
                log.info("文件记录删除成功，ID: {}", id);
            }
        } catch (Exception e) {
            log.error("删除文件记录失败，ID: {}", id, e);
        }
    }

    @Override
    public void deleteFileRecords(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }

        try {
            int result = fileRecordMapper.deleteBatchIds(ids);
            log.info("批量删除文件记录成功，数量: {}", result);
        } catch (Exception e) {
            log.error("批量删除文件记录失败", e);
        }
    }

    @Override
    public boolean isFileDuplicate(String fileHash) {
        if (fileHash == null || fileHash.trim().isEmpty()) {
            return false;
        }

        FileRecord existingFile = fileRecordMapper.selectByFileHash(fileHash);
        return existingFile != null;
    }

    @Override
    public Map<String, Object> getFileStatistics(String fileCategory) {
        Map<String, Object> statistics = new HashMap<>();

        try {
            // 文件总数
            Integer totalCount = fileRecordMapper.countByCategory(fileCategory);
            statistics.put("totalCount", totalCount);

            // 文件总大小
            Long totalSize = fileRecordMapper.sumFileSize(fileCategory);
            statistics.put("totalSize", totalSize);
            statistics.put("totalSizeMB", totalSize != null ? totalSize / (1024 * 1024.0) : 0);

            // 最近上传的文件
            QueryWrapper<FileRecord> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("deleted", 0);
            if (fileCategory != null) {
                queryWrapper.eq("file_category", fileCategory);
            }
            queryWrapper.orderByDesc("create_time");
            queryWrapper.last("LIMIT 10");
            List<FileRecord> recentFiles = fileRecordMapper.selectList(queryWrapper);
            statistics.put("recentFiles", recentFiles);

        } catch (Exception e) {
            log.error("获取文件统计信息失败", e);
            statistics.put("error", "获取统计信息失败");
        }

        return statistics;
    }

    @Override
    public int cleanExpiredFiles() {
        try {
            List<FileRecord> expiredFiles = fileRecordMapper.selectExpiredFiles(LocalDateTime.now());
            if (expiredFiles.isEmpty()) {
                log.info("没有找到过期的文件记录");
                return 0;
            }

            int deletedCount = 0;
            for (FileRecord file : expiredFiles) {
                try {
                    deleteFileRecord(file.getId());
                    deletedCount++;
                } catch (Exception e) {
                    log.error("删除过期文件记录失败，ID: {}", file.getId(), e);
                }
            }

            log.info("清理过期文件记录完成，删除数量: {}", deletedCount);
            return deletedCount;

        } catch (Exception e) {
            log.error("清理过期文件记录失败", e);
            return 0;
        }
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }

        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return ip;
    }

    /**
     * 计算文件哈希值（简化版本，实际项目中可以考虑更高效的算法）
     */
    private String calculateFileHash(MultipartFile file) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");

            // 使用文件名和大小组合计算哈希（避免读取整个文件内容）
            String fileInfo = file.getOriginalFilename() + file.getSize() + file.getContentType();

            byte[] hashBytes = md.digest(fileInfo.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : hashBytes) {
                sb.append(String.format("%02x", b));
            }

            return sb.toString();

        } catch (NoSuchAlgorithmException e) {
            log.error("计算文件哈希值失败", e);
            // 如果MD5不可用，使用简单的字符串哈希
            return String.valueOf((file.getOriginalFilename() + file.getSize()).hashCode());
        } catch (Exception e) {
            log.error("计算文件哈希值时发生错误", e);
            return "unknown-" + System.currentTimeMillis();
        }
    }
}